package gui;

import entities.Album;
import entities.Playlist;
import entities.Song;
import helpers.DBHelper;
import helpers.UIHelper;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


// Λίστες Τραγουδιών
public class PlaylistsForm extends javax.swing.JInternalFrame {
    private final DateFormat df = new SimpleDateFormat("dd/MM/yyyy");

    public PlaylistsForm() {
        initComponents();
    }
    
    // Ανανέωση Δεδομένων από τη ΒΔ
    private void refresh()
    {
        list.clear();
        list.addAll( query.getResultList());
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        em = java.beans.Beans.isDesignTime() ? null : javax.persistence.Persistence.createEntityManagerFactory("KLMRadioStationPU").createEntityManager();
        query = java.beans.Beans.isDesignTime() ? null : em.createQuery("SELECT p FROM Playlist p");
        list = java.beans.Beans.isDesignTime() ? java.util.Collections.emptyList() : org.jdesktop.observablecollections.ObservableCollections.observableList(query.getResultList());
        fileChooser = new javax.swing.JFileChooser();
        newButton = new javax.swing.JButton();
        editButton = new javax.swing.JButton();
        deleteButton = new javax.swing.JButton();
        jScrollPane2 = new javax.swing.JScrollPane();
        table = new javax.swing.JTable();
        xmlOutButton = new javax.swing.JButton();
        xmlInButton = new javax.swing.JButton();
        closeButton = new javax.swing.JButton();

        fileChooser.setDialogType(javax.swing.JFileChooser.SAVE_DIALOG);
        fileChooser.setDialogTitle("Εξαγωγή Λίστας σε XML");
        fileChooser.setFileFilter(new FileNameExtensionFilter("xml files (*.xml)", "xml"));

        setClosable(true);
        setMaximizable(true);
        setResizable(true);
        setTitle("Λίστες Τραγουδιών");
        setMinimumSize(new java.awt.Dimension(600, 300));
        setName(""); // NOI18N
        setPreferredSize(new java.awt.Dimension(600, 300));

        newButton.setText("Δημιουργία...");
        newButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newButtonActionPerformed(evt);
            }
        });

        editButton.setText("Ενημέρωση...");
        editButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editButtonActionPerformed(evt);
            }
        });

        deleteButton.setText("Διαγραφή");
        deleteButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                deleteButtonActionPerformed(evt);
            }
        });

        table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);

        org.jdesktop.swingbinding.JTableBinding jTableBinding = org.jdesktop.swingbinding.SwingBindings.createJTableBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, list, table);
        org.jdesktop.swingbinding.JTableBinding.ColumnBinding columnBinding = jTableBinding.addColumnBinding(org.jdesktop.beansbinding.ELProperty.create("${name}"));
        columnBinding.setColumnName("Όνομα Λίστας");
        columnBinding.setColumnClass(String.class);
        columnBinding.setEditable(false);
        columnBinding = jTableBinding.addColumnBinding(org.jdesktop.beansbinding.ELProperty.create("${creationDate}"));
        columnBinding.setColumnName("Ημερομηνία Ενημέρωσης");
        columnBinding.setColumnClass(java.util.Date.class);
        columnBinding.setEditable(false);
        bindingGroup.addBinding(jTableBinding);
        jTableBinding.bind();
        jScrollPane2.setViewportView(table);

        xmlOutButton.setText("Εξαγωγή σε XML");
        xmlOutButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                xmlOutButtonActionPerformed(evt);
            }
        });

        xmlInButton.setText("Εισαγωγή από XML");
        xmlInButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                xmlInButtonActionPerformed(evt);
            }
        });

        closeButton.setText("Κλείσιμο");
        closeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 269, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(xmlOutButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(newButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(editButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(deleteButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(xmlInButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(closeButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(newButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(editButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(deleteButton)
                        .addGap(40, 40, 40)
                        .addComponent(xmlOutButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(xmlInButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 78, Short.MAX_VALUE)
                        .addComponent(closeButton))
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
                .addContainerGap())
        );

        getAccessibleContext().setAccessibleName("Αρχείο Συγκροτημάτων");

        bindingGroup.bind();

        pack();
    }// </editor-fold>//GEN-END:initComponents
    
    // Event Handler Κουμπιού "Εισαγωγή"
    private void newButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newButtonActionPerformed
        PlaylistForm dialog = new PlaylistForm();
        dialog.setVisible(true);
        if(dialog.getDialogResult().equals("Save"))
        {
            DBHelper.persist(this, em, dialog.getEntity());
            refresh();
        }
    }//GEN-LAST:event_newButtonActionPerformed

    // Event Handler Κουμπιού "Επεξεργασία"
    private void editButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editButtonActionPerformed
        if (table.getSelectedRow() == -1) {
            return;
        }
        Playlist entity = list.get(table.convertRowIndexToModel(table.getSelectedRow()));
        PlaylistForm dialog = new PlaylistForm(entity);
        dialog.setVisible(true);
        if(dialog.getDialogResult().equals("Save"))
        {
            entity = dialog.getEntity();
            DBHelper.update(this, em, entity);
            
            refresh();
        }
    }//GEN-LAST:event_editButtonActionPerformed

    // Event Handler Κουμπιού "Διαγραφή"
    private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed
        if (table.getSelectedRow() == -1) {
            return;
        }
        Playlist entity = list.get(table.convertRowIndexToModel(table.getSelectedRow()));
        
        if (UIHelper.showDeleteConfirmation(this)) {
            DBHelper.delete(this, em, entity);
            refresh();
        }
    }//GEN-LAST:event_deleteButtonActionPerformed

    // Εξαγωγή Λίστας σε XML αρχείο
    private void xmlOutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_xmlOutButtonActionPerformed
        //Ερώτηση χρήστη για το όνομα αρχείου προς εξαγωγή
        fileChooser.setDialogType(javax.swing.JFileChooser.SAVE_DIALOG);
        fileChooser.setDialogTitle("Εξαγωγή Λίστας σε XML");
        int status = fileChooser.showSaveDialog(null);
        String fileName = fileChooser.getSelectedFile().getAbsolutePath();
        if(status != JFileChooser.APPROVE_OPTION) 
            return; //εαν ο χρήστης πατήσει ακύρωση, μην προχωρήσεις
        
        try{
            Playlist result = list.get(table.convertRowIndexToModel(table.getSelectedRow()));
            // Δημιουργία parser που παράγει το DOM XML αρχείων
            DocumentBuilderFactory docFactory =
                DocumentBuilderFactory.newInstance(); 
            // αναφέρεται στο XML αρχείο,είναι η ιδεατή ρίζα του δέντρου
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
            // αναφέρεται στο XML αρχείο,είναι η ιδεατή ρίζα του δέντρου
            Document doc = docBuilder.newDocument();
            // δημιουργώ την ρίζα playlist
            Element playlist = doc.createElement("playlist"); // δημιουργώ ένα στοιχείο με το όνομα playlist
            doc.appendChild(playlist); // τον συνδέω ως το κύριο(root) κόμβο
            Attr attr = doc.createAttribute("id"); //ο κόμβος αυτός έχει ένα χαρακτηριστικό το id (είναι η ιδιότητα id του Playlist
            attr.setValue(Integer.toString(result.getId())); // σαν τιμή θα πάρει id του Playlist, για αυτό καλώ τη συνάρτηση getId()
            playlist.setAttributeNode(attr);
            Element name = doc.createElement("name");
            name.appendChild(doc.createTextNode(result.getName())); // δημιουργώ τον κόμβο με το όνομα της λίστας
            playlist.appendChild(name);
            Element creationDate = doc.createElement("creationDate");
            creationDate.appendChild(doc.createTextNode(df.format(result.getCreationDate())));
            playlist.appendChild(creationDate);
            Element songList = doc.createElement("songList");
            playlist.appendChild(songList);
            for(Song sg: result.getSongList())
            {
                Element song = doc.createElement("song");
                songList.appendChild(song);
                Attr attr2 = doc.createAttribute("id");
                attr2.setValue(Integer.toString(sg.getId()));
                song.setAttributeNode(attr2);
                Element songTitle = doc.createElement("title");
                songTitle.appendChild(doc.createTextNode(sg.getTitle()));
                song.appendChild(songTitle);
                Element duration = doc.createElement("duration");
                duration.appendChild(doc.createTextNode(Integer.toString(sg.getDuration())));
                song.appendChild(duration);
                Element trackNr = doc.createElement("trackNr");
                trackNr.appendChild(doc.createTextNode(Integer.toString(sg.getTrackNr())));
                song.appendChild(trackNr);
                Element album = doc.createElement("album");
                song.appendChild(album);
                Attr attr3 = doc.createAttribute("id");
                attr3.setValue(Integer.toString(sg.getAlbumId().getId()));
                album.setAttributeNode(attr3);
                Element albumTitle = doc.createElement("title");
                albumTitle.appendChild(doc.createTextNode(sg.getAlbumId().getTitle()));
                album.appendChild(albumTitle);
                Element releaseDate = doc.createElement("releaseDate");
                releaseDate.appendChild(doc.createTextNode(df.format(sg.getAlbumId().getReleaseDate())));
                album.appendChild(releaseDate);
                Element type = doc.createElement("type");
                type.appendChild(doc.createTextNode(sg.getAlbumId().getType()));
                album.appendChild(type);
                Element diskNumber = doc.createElement("diskNumber");
                diskNumber.appendChild(doc.createTextNode(Integer.toString(sg.getAlbumId().getDiskNumber())));
                album.appendChild(diskNumber);
            }
            // γράφω όλα τα παραπάνω σε ένα αρχείο xml
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource source = new DOMSource(doc);
            StreamResult streamResult;
            //δημιουργώ το αρχείο xml
            streamResult = new StreamResult(new File(fileName));
            transformer.transform(source, streamResult);
            System.out.println("File saved!");
        }
        catch (ParserConfigurationException pce) {
            pce.printStackTrace();
            UIHelper.showError(this, pce.getMessage());
        } catch (TransformerException tfe) {
            tfe.printStackTrace();
            UIHelper.showError(this, tfe.getMessage());
        }
    }//GEN-LAST:event_xmlOutButtonActionPerformed

    // Εισαγωγή Λίστας από XML αρχείο
    private void xmlInButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_xmlInButtonActionPerformed
        //Ερώτηση χρήστη για το όνομα αρχείου προς εισαγωγή
        fileChooser.setDialogType(javax.swing.JFileChooser.OPEN_DIALOG);
        fileChooser.setDialogTitle("Εισαγωγή Λίστας από XML");
        int status = fileChooser.showOpenDialog(null);
        String fileName = fileChooser.getSelectedFile().getAbsolutePath();
        if(status != JFileChooser.APPROVE_OPTION)
            return; //εαν ο χρήστης πατήσει ακύρωση, μην προχωρήσεις
        
        try {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(fileName);
            
            NodeList nList = doc.getElementsByTagName("playlist");
            for(int i=0;i<nList.getLength();i++)
            {
                Node nNode = nList.item(i);
                Element eElement = (Element)nNode;
                Playlist playlist = new Playlist();
                playlist.setId(Integer.parseInt(eElement.getAttribute("id")));
                playlist.setName(eElement.getElementsByTagName("name").item(0).getTextContent());
                playlist.setCreationDate(df.parse(eElement.getElementsByTagName("creationDate").item(0).getTextContent()));
                ArrayList<Song> songList = new ArrayList<Song>();
                Element sElement = (Element)eElement.getElementsByTagName("songList").item(0);
                NodeList sList = sElement.getElementsByTagName("song");
                for(int j=0;j<sList.getLength();j++)
                {                    
                    Node sNode = sList.item(j);
                    Element songElement = (Element)sNode;
                    Song song = new Song();
                    song.setId(Integer.parseInt(songElement.getAttribute("id")));
                    song.setTitle(songElement.getElementsByTagName("title").item(0).getTextContent());
                    song.setDuration(Integer.parseInt(songElement.getElementsByTagName("duration").item(0).getTextContent()));
                    song.setTrackNr(Integer.parseInt(songElement.getElementsByTagName("trackNr").item(0).getTextContent()));
                    Element albumElement = (Element)songElement.getElementsByTagName("album").item(0);
                    Album album = new Album();
                    album.setId(Integer.parseInt(albumElement.getAttribute("id")));
                    album.setDiskNumber(Integer.parseInt(albumElement.getElementsByTagName("diskNumber").item(0).getTextContent()));
                    album.setTitle(albumElement.getElementsByTagName("title").item(0).getTextContent());
                    album.setReleaseDate(df.parse(albumElement.getElementsByTagName("releaseDate").item(0).getTextContent()));
                    album.setType(albumElement.getElementsByTagName("type").item(0).getTextContent());
                    song.setAlbumId(album);
                    songList.add(song);
                }
                playlist.setSongList(songList);
                
                em.getTransaction().begin();
                if(em.find(Playlist.class, playlist.getId()) == null)
                {
                    em.persist(playlist);
                }
                em.getTransaction().commit();

                refresh();
            }
        } 
        catch (Exception e){
            UIHelper.showError(this, e.getMessage());
        }
    }//GEN-LAST:event_xmlInButtonActionPerformed

    //Κλείνει την φόρμα
    private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
        this.dispose();
    }//GEN-LAST:event_closeButtonActionPerformed


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton closeButton;
    private javax.swing.JButton deleteButton;
    private javax.swing.JButton editButton;
    private javax.persistence.EntityManager em;
    private javax.swing.JFileChooser fileChooser;
    private javax.swing.JScrollPane jScrollPane2;
    private java.util.List<entities.Playlist> list;
    private javax.swing.JButton newButton;
    private javax.persistence.Query query;
    private javax.swing.JTable table;
    private javax.swing.JButton xmlInButton;
    private javax.swing.JButton xmlOutButton;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables
}
